package org.opengauss.datachecker.extract.data.access;

import org.opengauss.datachecker.common.entry.common.DataAccessParam;
import org.opengauss.datachecker.common.entry.common.Health;
import org.opengauss.datachecker.common.entry.extract.ColumnsMetaData;
import org.opengauss.datachecker.common.entry.extract.PrimaryColumnBean;
import org.opengauss.datachecker.common.entry.extract.TableMetadata;
import org.opengauss.datachecker.extract.data.mapper.SqlServerMetaDataMapper;

import java.sql.Connection;
import java.util.List;

/**
 * SqlServerDataAccessService
这是一个用于 SQL Server 数据库的数据访问服务类。
它继承自 AbstractDataAccessService，并实现了数据库特定的操作方法。
sqlMode 方法：SQL Server 没有直接等效于 MySQL 的 SQL 模式设置，因此返回说明信息。
health 方法：使用 SQL Server 的信息模式查询 schema 的存在性来检查数据库健康状态。
dasQueryTableNameList 方法：查询当前 schema 中所有表的名称，使用 SQL Server 的信息模式。
queryTableColumnsMetaData 方法：查询指定表的列元数据。
queryTableMetadata 方法：查询指定表的元数据，并将结果包装成 TableMetadata 对象。
queryTablePrimaryColumns 方法：查询当前 schema 中所有表的主键列。
queryTablePrimaryColumns(String tableName) 方法：查询指定表的主键列。
dasQueryTableMetadataList 方法：查询当前 schema 中所有表的元数据列表。
rowCount 方法：查询指定表的行数。
min 方法：查询指定列的最小值。
max 方法：查询指定列的最大值。
next 方法：获取下一个值（具体实现依赖于 sqlServerMetaDataMapper）。
queryPointList 方法：使用 SQL Server 的窗口函数查询特定的点值。
dasCheckDatabaseNotEmpty 方法：检查数据库是否为空。
 */
public class SqlServerDataAccessService extends AbstractDataAccessService {
    private SqlServerMetaDataMapper sqlServerMetaDataMapper;

    public SqlServerDataAccessService(SqlServerMetaDataMapper sqlServerMetaDataMapper) {
        this.sqlServerMetaDataMapper = sqlServerMetaDataMapper;
    }

    @Override
    public String sqlMode() {
             //return sqlserverMetaDataMapper.sqlMode();
        // SQL Server 没有直接等效于 MySQL 的 SQL 模式设置
        return null;
    }

    @Override
    public Health health() {
        String schema = properties.getSchema();
        String sql = "SELECT SCHEMA_NAME AS tableSchema FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME='" + schema + "'";
        //String sql = "SELECT SCHEMA_NAME AS tableSchema FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME='zc_db'";
        return health(schema, sql);
    }

    @Override
    public boolean isOgCompatibilityB() {
        return false;
    }

    @Override
    public List<String> dasQueryTableNameList() {
        String schema = properties.getSchema();
        String sql = "SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA='" + schema + "'";
        return adasQueryTableNameList(sql);
    }

    @Override
    public List<ColumnsMetaData> queryTableColumnsMetaData(String tableName) {
        return sqlServerMetaDataMapper.queryTableColumnsMetaData(properties.getSchema(), tableName);
    }

    @Override
    public TableMetadata queryTableMetadata(String tableName) {
        return wrapperTableMetadata(sqlServerMetaDataMapper.queryTableMetadata(properties.getSchema(), tableName));
    }

    @Override
    public List<PrimaryColumnBean> queryTablePrimaryColumns() {
        String sql = "SELECT kcu.TABLE_NAME AS tableName, kcu.COLUMN_NAME AS columnName "
                + "FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS tc "
                + "JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE kcu "
                + "ON tc.CONSTRAINT_NAME = kcu.CONSTRAINT_NAME "
                + "AND tc.TABLE_NAME = kcu.TABLE_NAME "
                + "WHERE tc.TABLE_SCHEMA = '" + properties.getSchema() + "' "
                + "AND tc.CONSTRAINT_TYPE = 'PRIMARY KEY' "
                + "ORDER BY kcu.TABLE_NAME, kcu.ORDINAL_POSITION ASC";
        return adasQueryTablePrimaryColumns(sql);
    }


    @Override
    public List<PrimaryColumnBean> queryTablePrimaryColumns(String tableName) {
        return sqlServerMetaDataMapper.queryTablePrimaryColumnsByTableName(properties.getSchema(), tableName);
    }

    @Override
    public List<TableMetadata> dasQueryTableMetadataList() {
        String sql = "SELECT s.name AS tableSchema, t.name AS tableName, p.rows AS tableRows, "
                + "ISNULL(SUM(a.total_pages) * 8 / NULLIF(p.rows, 0), 0) AS avgRowLength "
                + "FROM sys.tables t "
                + "JOIN sys.schemas s ON t.schema_id = s.schema_id "
                + "JOIN sys.partitions p ON t.object_id = p.object_id "
                + "JOIN sys.allocation_units a ON p.partition_id = a.container_id "
                + "WHERE s.name = '" + properties.getSchema() + "' "
                + "GROUP BY s.name, t.name, p.rows";
        return wrapperTableMetadata(adasQueryTableMetadataList(sql));
    }

    @Override
    public long rowCount(String tableName) {
        return sqlServerMetaDataMapper.rowCount(properties.getSchema(), tableName);
    }

    @Override
    public String min(Connection connection, DataAccessParam param) {
        String sql = "SELECT MIN(" + param.getColName() + ") FROM " + param.getSchema() + "." + param.getName();
        return adasQueryOnePoint(connection, sql);
    }

    @Override
    public String max(Connection connection, DataAccessParam param) {
        String sql = "SELECT MAX(" + param.getColName() + ") FROM " + param.getSchema() + "." + param.getName();
        return adasQueryOnePoint(connection, sql);
    }

    @Override
    public String next(DataAccessParam param) {
        return sqlServerMetaDataMapper.next(param);
    }

    @Override
    public List<Object> queryPointList(Connection connection, DataAccessParam param) {
        String sql = "WITH cte AS (SELECT ROW_NUMBER() OVER (ORDER BY " + param.getColName() + ") AS rn, "
            + param.getColName() + " FROM " + param.getSchema() + "." + param.getName() + ") "
            + "SELECT " + param.getColName() + " FROM cte WHERE (rn % " + param.getOffset() + ") = 1";
        return adasQueryPointList(connection, sql);
    }

    @Override
    public boolean dasCheckDatabaseNotEmpty() {
        return sqlServerMetaDataMapper.checkDatabaseNotEmpty(properties.getSchema());
    }
}
